{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "import random\n",
    "from typing import Dict, Any, List\n",
    "from contextlib import contextmanager\n",
    "\n",
    "import opik\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " # Dynamic Tracing Control Cookbook\n",
    "\n",
    "\n",
    "\n",
    " This cookbook demonstrates how to use Opik's dynamic tracing control features\n",
    "\n",
    " to optimize performance and implement flexible tracing strategies in production.\n",
    "\n",
    "\n",
    "\n",
    " ## What You'll Learn:\n",
    "\n",
    " - Enable/disable tracing at runtime without code changes\n",
    "\n",
    " - Implement conditional tracing based on user attributes\n",
    "\n",
    " - Create sampling strategies for high-throughput systems\n",
    "\n",
    " - Measure and optimize tracing performance impact\n",
    "\n",
    " - Control integration tracking dynamically\n",
    "\n",
    "\n",
    "\n",
    " ## Prerequisites:\n",
    "\n",
    " ```bash\n",
    "\n",
    " pip install opik\n",
    "\n",
    " ```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " ## Setup and Imports\n",
    "\n",
    "\n",
    "\n",
    " First, let's import the necessary libraries and set up our environment."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Opik version: 1.8.7\n",
      "Initial tracing state: True\n"
     ]
    }
   ],
   "source": [
    "print(f\"Opik version: {opik.__version__}\")\n",
    "print(f\"Initial tracing state: {opik.is_tracing_active()}\") # the opposite of the track_disable\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " ## 1. Basic Runtime Control\n",
    "\n",
    "\n",
    "\n",
    " The simplest use case is toggling tracing on and off during runtime."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Current tracing state: True\n",
      "After disabling: False\n",
      "After enabling: True\n"
     ]
    }
   ],
   "source": [
    "print(f\"Current tracing state: {opik.is_tracing_active()}\")\n",
    "\n",
    "opik.set_tracing_active(False)\n",
    "print(f\"After disabling: {opik.is_tracing_active()}\")\n",
    "\n",
    "opik.set_tracing_active(True)\n",
    "print(f\"After enabling: {opik.is_tracing_active()}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " ## 2. Context-Aware Tracing\n",
    "\n",
    "\n",
    "\n",
    " Create a context manager for temporary tracing control."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Before context: True\n",
      "Inside context (disabled): False\n",
      "After context: True\n"
     ]
    }
   ],
   "source": [
    "@contextmanager\n",
    "def tracing_enabled(enabled: bool):\n",
    "    \"\"\"Context manager for temporary tracing control.\"\"\"\n",
    "    original_state = opik.is_tracing_active()\n",
    "    try:\n",
    "        opik.set_tracing_active(enabled)\n",
    "        yield\n",
    "    finally:\n",
    "        opik.set_tracing_active(original_state)\n",
    "\n",
    "print(f\"Before context: {opik.is_tracing_active()}\")\n",
    "\n",
    "with tracing_enabled(False):\n",
    "    print(f\"Inside context (disabled): {opik.is_tracing_active()}\")\n",
    "    # ny traced functions here won't create spans\n",
    "\n",
    "print(f\"After context: {opik.is_tracing_active()}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " ## 3. Conditional Tracing Strategies\n",
    "\n",
    "\n",
    "\n",
    " Implement different strategies for when to enable tracing (see part 4 for connection)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TracingStrategy:\n",
    "    \"\"\"Base class for tracing strategies.\"\"\"\n",
    "\n",
    "    def should_trace(self, **kwargs) -> bool:\n",
    "        \"\"\"Determine if tracing should be enabled for this request.\"\"\"\n",
    "        raise NotImplementedError\n",
    "\n",
    "\n",
    "class UserTierStrategy(TracingStrategy):\n",
    "    \"\"\"Trace only premium users.\"\"\"\n",
    "\n",
    "    def __init__(self, premium_tiers: List[str] = None):\n",
    "        self.premium_tiers = premium_tiers or [\"premium\", \"enterprise\"]\n",
    "\n",
    "    def should_trace(self, user_tier: str = None, **kwargs) -> bool:\n",
    "        return user_tier in self.premium_tiers\n",
    "\n",
    "\n",
    "class SamplingStrategy(TracingStrategy):\n",
    "    \"\"\"Trace a percentage of requests.\"\"\"\n",
    "\n",
    "    def __init__(self, sample_rate: float = 0.1):\n",
    "        self.sample_rate = sample_rate\n",
    "\n",
    "    def should_trace(self, **kwargs) -> bool:\n",
    "        return random.random() < self.sample_rate\n",
    "\n",
    "\n",
    "class DebugModeStrategy(TracingStrategy):\n",
    "    \"\"\"Trace when in debug mode or for specific users.\"\"\"\n",
    "\n",
    "    def __init__(self, debug_users: List[str] = None):\n",
    "        self.debug_users = debug_users or []\n",
    "        self.debug_mode = False\n",
    "\n",
    "    def should_trace(self, user_id: str = None, **kwargs) -> bool:\n",
    "        return self.debug_mode or (user_id in self.debug_users)\n",
    "\n",
    "    def enable_debug(self):\n",
    "        self.debug_mode = True\n",
    "\n",
    "    def disable_debug(self):\n",
    "        self.debug_mode = False\n",
    "\n",
    "strategies = {\n",
    "    \"premium_only\": UserTierStrategy(),\n",
    "    \"10_percent_sample\": SamplingStrategy(0.1),\n",
    "    \"debug_mode\": DebugModeStrategy([\"debug_user_1\", \"debug_user_2\"]),\n",
    "}\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " ## 4. Smart Request Handler\n",
    "\n",
    "\n",
    "\n",
    " Create a request handler that uses tracing strategies."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "=== Testing Premium-Only Strategy ===\n",
      "User user1 (free): Traced = False\n",
      "User user2 (premium): Traced = True\n",
      "User user3 (free): Traced = False\n",
      "User user4 (enterprise): Traced = True\n"
     ]
    }
   ],
   "source": [
    "@opik.track(name=\"user_query\")\n",
    "def handle_user_query(query: str, user_id: str, user_tier: str) -> Dict[str, Any]:\n",
    "    \"\"\"Simulate handling a user query with LLM processing.\"\"\"\n",
    "    time.sleep(0.01)\n",
    "    \n",
    "    if user_tier in [\"premium\", \"enterprise\"]:\n",
    "        response = f\"Premium response to: {query}\"\n",
    "        tokens_used = random.randint(150, 300)\n",
    "    else:\n",
    "        response = f\"Basic response to: {query}\"\n",
    "        tokens_used = random.randint(50, 100)\n",
    "    \n",
    "    return {\n",
    "        \"query\": query,\n",
    "        \"response\": response,\n",
    "        \"user_id\": user_id,\n",
    "        \"user_tier\": user_tier,\n",
    "        \"tokens_used\": tokens_used,\n",
    "        \"processing_time_ms\": random.randint(100, 500)\n",
    "    }\n",
    "\n",
    "\n",
    "\n",
    "class SmartRequestHandler:\n",
    "    \"\"\"Request handler with configurable tracing strategy.\"\"\"\n",
    "\n",
    "    def __init__(self, strategy: TracingStrategy):\n",
    "        self.strategy = strategy\n",
    "\n",
    "    def handle_request(\n",
    "        self, query: str, user_id: str, user_tier: str\n",
    "    ) -> Dict[str, Any]:\n",
    "        \"\"\"Handle request with conditional tracing.\"\"\"\n",
    "\n",
    "        should_trace = self.strategy.should_trace(\n",
    "            user_id=user_id, user_tier=user_tier, query=query\n",
    "        )\n",
    "\n",
    "        opik.set_tracing_active(should_trace)\n",
    "\n",
    "\n",
    "        response_and_metadata = handle_user_query(query, user_id, user_tier)\n",
    "\n",
    "        return {\n",
    "            \"traced\": should_trace,\n",
    "            \"result\": response_and_metadata,\n",
    "        }\n",
    "\n",
    "\n",
    "print(\"=== Testing Premium-Only Strategy ===\")\n",
    "handler = SmartRequestHandler(UserTierStrategy())\n",
    "\n",
    "requests = [\n",
    "    (\"What is AI?\", \"user1\", \"free\"),\n",
    "    (\"Explain ML\", \"user2\", \"premium\"),\n",
    "    (\"How does it work?\", \"user3\", \"free\"),\n",
    "    (\"Advanced question\", \"user4\", \"enterprise\"),\n",
    "]\n",
    "\n",
    "for query, user_id, tier in requests:\n",
    "    result = handler.handle_request(query, user_id, tier)\n",
    "    print(f\"User {user_id} ({tier}): Traced = {result['traced']}\")\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
